﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;
using System.Drawing;

namespace HiddenFileManager
{
    enum ItemStatus { Visible, Hidden, NotExist, NotAccessible  }

    class FileItem : ListViewItem, IComparable
    {
        public readonly String FullPath;

        public FileItem(String fullPath)
        {
            FullPath = fullPath;

            UpdateListViewItem();
        }

        /// <summary>
        /// Gets or sets the status of the item
        /// </summary>
        /// <throws>ApplicationException if status cannot be set.</throws>
        public ItemStatus Status
        {
            get 
            {
                // TODO: possibly cache the status, so we don't
                // have to try accessing the file every time
                // (may be slow over network connections etc.)

                FileSystemInfo itemInfo = GetInfo(FullPath);
                if (itemInfo == null) { return ItemStatus.NotExist; }

                try
                {
                    FileAttributes at = itemInfo.Attributes;
                    return (at & FileAttributes.Hidden) == 0 ?
                        ItemStatus.Visible : ItemStatus.Hidden; 
                }
                catch (Exception e)
                {
                    Trace.TraceError("Not accessible: " + FullPath + "\r\n" + e);
                    return ItemStatus.NotAccessible;
                }
            }
        }

        public void SetHidden(bool value)
        {
            // Try setting the hidden status
            FileSystemInfo itemInfo = GetInfo(FullPath);
            if (itemInfo == null) { throw new ApplicationException("Item does not exist: " + FullPath); }
            try
            {
                if (value)
                {
                    itemInfo.Attributes |= FileAttributes.Hidden;
                }
                else 
                {
                    itemInfo.Attributes &= ~FileAttributes.Hidden;
                }
            }
            catch (Exception e)
            {
                throw new ApplicationException("Cannot set Hidden attribute on: " + FullPath, e);
            }

            UpdateListViewItem();
        }

        #region ListViewItem update

        void UpdateListViewItem()
        {
            // ListViewItem properties
            ItemStatus s = this.Status;
            if (s.ToString() != base.Text)
            {
                base.Text = s.ToString();
                base.ForeColor = GetItemForeColor(s);
                base.BackColor = GetItemBackColor(s);
                base.Checked = (s == ItemStatus.Hidden);
            }

            if (base.SubItems.Count < 3)
            {
                // First one is the main item
                base.SubItems.Add(new ListViewSubItem());
                base.SubItems.Add(new ListViewSubItem());
            }

            if (FileName != base.SubItems[1].Text)
            {
                base.SubItems[1].Text = FileName;
            }
            if (Path != base.SubItems[2].Text)
            {
                base.SubItems[2].Text = Path;
            }
        }

        static Color GetItemForeColor(ItemStatus status)
        {
            switch (status)
            {
                case ItemStatus.NotAccessible:
                    return Color.Red;
                case ItemStatus.NotExist:
                    return Color.DarkRed;
                default:
                    return Color.Black;
            }
        }
        static Color GetItemBackColor(ItemStatus status)
        {
            switch (status)
            {
                case ItemStatus.Hidden:
                    return Color.LightGray;
                default:
                    return SystemColors.Window;
            }
        }




        #endregion

        static FileSystemInfo GetInfo(String path)
        {
            if (Directory.Exists(path))
            {
                return new DirectoryInfo(path);
            }
            if (File.Exists(path))
            {
                return new FileInfo(path);
            }
            return null;
        }


        // TODO: file type/icon

        public String Path
        {
            get { return System.IO.Path.GetDirectoryName(FullPath); }
        }

        public String FileName
        {
            get { return System.IO.Path.GetFileName(FullPath); }
        }

        #region IComparable Members

        public int CompareTo(object obj)
        {
            FileItem that = obj as FileItem;
            if (that == null) { return -1; }
            return this.FullPath.CompareTo(that.FullPath);
        }

        #endregion

        public override bool Equals(object obj)
        {
            FileItem that = obj as FileItem;
            if (that == null) { return false; }
            return FullPath.Equals(that.FullPath);
        }

        public override int GetHashCode()
        {
            return FullPath.GetHashCode();
        }

        public override string ToString()
        {
            return FullPath;
        }
    }
}
